package com.css.cloudlearn.productornacos.route;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.css.dynamic.conanst.CacheConstants;
import com.css.dynamic.dynamicRoute.RouteDefinitionVo;
import com.css.dynamic.event.DynamicRouteInitEvent;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author 郭辉
 * @className TODO
 * @description TODO
 * @date 2022/11/2 8:51
 * @company 海康威视
 * @since 1.0.0
 */
@AllArgsConstructor
@Slf4j
@RestController
@RequestMapping("/api/route")
public class RouteController {
    private RedisTemplate redisTemplate;

    private ApplicationEventPublisher applicationEventPublisher;
//    @Autowired
//    private DynamicRouteEventPublisher applicationEventPublisher;
    @PostMapping("/saveOrUpdate")
    public Mono<Object> routeAdd(@RequestBody RouteDefinitionVo param) {
        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(stringSerializer);
        //从redis中获取所有路由信息
        List<RouteDefinitionVo> routes = new ArrayList<>();
        //处理新的路由数据
//        redisTemplate.setKeySerializer(new StringRedisSerializer());
//        redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(String.class));
        Set<String> keys = redisTemplate.opsForHash().keys(CacheConstants.ROUTE_KEY);
        for (String key : keys) {
            redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(RouteDefinitionVo.class));
            RouteDefinitionVo routeDefinitionVo = (RouteDefinitionVo) redisTemplate.opsForHash().get(CacheConstants.ROUTE_KEY, key);
            routes.add(routeDefinitionVo);
        }
        //清除redis中的路由信息
        Boolean result = redisTemplate.delete(CacheConstants.ROUTE_KEY);
        log.info("清空网关路由 {} ", result);

        // 遍历修改的routes，保存到Redis
        List<RouteDefinitionVo> routeDefinitionVoList = new ArrayList<>();
        Iterator<RouteDefinitionVo> iterator = routeDefinitionVoList.iterator();
        while (iterator.hasNext()){
            RouteDefinitionVo next = iterator.next();
            if (next.getId().equals(param.getId())){
                iterator.remove();
            }
        }
        routes.add(param);
        try {
            routes.forEach(value -> {
                log.info("更新路由 ->{}", value);
                RouteDefinitionVo vo = new RouteDefinitionVo();
                Map<String, Object> map = BeanMap.create(value);

//				Object id = map.get("routeId");
                Object id = map.get("id");
                if (id != null) {
                    vo.setId(String.valueOf(id));
                }

                Object routeName = map.get("routeName");
                if (routeName != null) {
                    vo.setRouteName(String.valueOf(routeName));
                }

                Object predicates = map.get("predicates");
                if (predicates != null) {
                    JSONArray predicatesArray = JSON.parseArray(JSON.toJSONString(predicates));
                    List<PredicateDefinition> predicateDefinitionList =
                            predicatesArray.toJavaList(PredicateDefinition.class);
                    vo.setPredicates(predicateDefinitionList);
                }

                Object filters = map.get("filters");
                if (ObjectUtils.isNotEmpty(filters)) {
                    JSONArray filtersArray = (JSONArray) filters;
                    List<FilterDefinition> filterDefinitionList
                            = filtersArray.toJavaList(FilterDefinition.class);
                    vo.setFilters(filterDefinitionList);
                }

                Object uri = map.get("uri");
                if (uri != null) {
                    vo.setUri(URI.create(String.valueOf(uri)));
                }

                Object order = map.get("order");
                if (order != null) {
                    vo.setOrder(Integer.parseInt(String.valueOf(order)));
                }
                //遍历新的路由列表，保存到redis
                redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(String.class));
                redisTemplate.opsForHash().put(CacheConstants.ROUTE_KEY, vo.getId(), vo);
                routeDefinitionVoList.add(vo);
            });


            log.debug("更新网关路由结束 ");

            //发布网关路由更新事件
            this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
//            this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(123456654));
            //产生redis消息，网关路由更新缓存
            redisTemplate.convertAndSend(CacheConstants.ROUTE_JVM_RELOAD_TOPIC, "UPMS路由信息,网关缓存更新");
        } catch (Exception e) {
            log.error("路由配置解析失败", e);
            // 回滚路由，重新加载即可
            this.applicationEventPublisher.publishEvent(new DynamicRouteInitEvent(this));
            // 抛出异常
            throw new RuntimeException(e);
        }
        return Mono.empty();
    }



    //路由删除
    /*@GetMapping("/deleteRoute")
    public Mono<Object> routeDelete(@RequestHeader("id") String id) {
        try {
            RedisSerializer stringSerializer = new StringRedisSerializer();
            redisTemplate.setKeySerializer(stringSerializer);
            redisTemplate.setValueSerializer(stringSerializer);
            redisTemplate.setHashKeySerializer(stringSerializer);
            redisTemplate.setHashValueSerializer(stringSerializer);
            redisTemplate.opsForHash().delete(CacheConstants.ROUTE_KEY, id);
            this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
            redisTemplate.convertAndSend(CacheConstants.ROUTE_JVM_RELOAD_TOPIC, "UPMS路由信息,网关缓存更新");
        } catch (Exception e){
            log.error("路由删除失败", e);
            // 回滚路由，重新加载即可
//            this.applicationEventPublisher.publishEvent(new DynamicRouteInitEvent(this));
            this.applicationEventPublisher.publish();
            // 抛出异常
            throw new RuntimeException(e);
        }
        return Mono.empty();
    }*/
}
